Revision:
if there are no parameters, you can place an empty parentheses before "=>". example: () => 42
In fact, you don't even need the parentheses! example: _ => 42
examples
<div> <p class="spec" id="func3"></p> <p class="spec" id="func4"></p> </div> <script> var myfunc3 = () => { document.getElementById("func3").innerHTML ="This is an arrow function."; }; var myfunc4 = _ => { document.getElementById("func4").innerHTML ="This is an aonther arrow function."; }; myfunc3(); myfunc4(); </script>
with these functions, parentheses are optional.example: x => 42 || (x) => 42
Long version: examples
greet somebody =>
<p> greet somebody => <span id="arrow"></span></p> <script> const greet = (who) => { return `Hello, ${who}!`; }; result = greet('Eddy Merckx'); document.getElementById("arrow").innerHTML = result; </script>
Omitting parenthesis: examples
greet somebody =>
<p>< greet somebody => <span id="arrow3"></span></p> <script> const greet1 = who => { return `Hello, ${who}!`; }; result1 = greet1('Paul Van Himst'); document.getElementById("arrow3").innerHTML = result1; </script>
Long version: examples
double the numbers 4, 5, 2, 6 =>
<div> <p class="spec">double the numbers 4, 5, 2, 6 =><span id="arrow2"></span></p> </div> <script> const numbers = [4, 5, 2, 6]; const doubled = numbers.map((number) => { return number * 2; }); document.getElementById("arrow2").innerHTML = doubled; </script>
parentheses are required for these functions. example: (x, y, z) => 42
with the arrow function, statements need to have curly braces. Once the curly braces are present, you always need to write "return" as well.
example:
var feedTheCat = (cat) => { if (cat === 'hungry') { return 'Feed the cat'; } else { return 'Do not feed the cat'; } }
if your function is in a block, you must also use the explicit return statement.
example:
var addValues = (x, y) => { return x + y }
if you are returning an object literal, it needs to be wrapped in parentheses. This forces the interpreter to evaluate what is inside the parentheses, and the object literal is returned. example: x =>({ y: x })
MAIN BENEFIT: no binding of "this".
In classic function expressions, the "this" keyword is bound to different values based on the "context" in which it is called. With arrow functions however, this is "lexically" bound. It means that it uses "this" from the code that contains the arrow function.
1/ Items in a list. One of the primary usecases for arrow functions in JavaScript is for functions that get applied over and over again to items in a list.
If you have an array of values that you want to transform using a map, an arrow function is ideal. A common example of this is to pull out a particular value of an object.
2/ Promises and promise chains. Another place arrow functions make for cleaner and more intuitive code is in managing asynchronous code.
Promises make it far easier to manage async code. This is an ideal location for an arrow function, especially if your resulting function is stateful, referencing something in your object.
3/ Object transformations Another common and extremely powerful use for arrow functions is to encapsulate object transformations.
These sorts of simple transformations are an ideal and beautiful place to utilize arrow functions.
1/ Object methods. When using an arrow function "this" is not bound to anything and it just inherits it from the parent scope, which in many cases is the window.
2/ Callback functions with dynamic context. If you need your context to be dynamic, arrow functions are not the right choice.
3/ When it makes your code less readable.With regular functions, people know what to expect. With arrow functions, it may be hard to decipher what you are looking at straightaway.
The most important thing to remember about arrow functions is the way they handle the "this" keyword. In particular, the "this" keyword inside an arrow function doesn't get rebound.
Arrow functions do not have "this". If "this" is accessed, it is taken from the outside.
examples: arrow function and "this" keyword
<div class="container"> <button class="start-btn">Start Counter</button> </div> <script> const startBtn = document.querySelector(".start-btn"); startBtn.addEventListener('click', function() { this.classList.add('counting') let counter = 10; let timer = setInterval(() => { this.textContent = counter counter -- if(counter < 0) { this.textContent = 'THE END!' this.classList.remove('counting') clearInterval(timer) } }, 1000) }) </script>
examples: error
<p style="margin-left:5vw;"><span id="car"></span> </p> <script> const car = { model: 'Fiesta', manufacturer: 'Ford', fullName: () => { return `${this.manufacturer} ${this.model}` } } car.fullName(); console.log(car.fullname); document.getElementById("car").innerHTML = car.fullname; </script>
If the arrow function "accepts a rest parameter", "destructures the parameter" or "has no parameters", then you have to keep the parentheses.
rest parameter: examples
greet somebody =>
<p class="spec">greet somebody => <span id="arrow4"></span></p> <script> const greetObject = ({ name }) => { return `Hello, ${name}!`; } result2 = greetObject({ name: 'Eric' }); // => 'Hello, Eric!' document.getElementById("arrow4").innerHTML = result2; </script>
destructuring parameters: examples
greet somebody =>
<p class="spec">greet somebody => <span id="arrow5"></span></p> <script> const greetPeople = (...args) => { return `Hello, ${args.join(' and ')}!`; } result3 = greetPeople('Eric', 'Stan'); // => 'Hello, Eric and Stan!' document.getElementById("arrow5").innerHTML = result3; </script>
no parameters: examples
greet somebody =>
<p class="spec">no parameters - greet somebody => <span id="arrow6"></span></p> <script> const sayHello = () => { return 'Hello!'; } result4 = sayHello(); // => Hello document.getElementById("arrow6").innerHTML = result4; </script>
omitting curly braces: examples
greet somebody =>
<p><b>greet somebody => <span id="arrow7"></span></p> <script> const greetSomebody = who => `Hello, ${who}!`; result5 = greetSomebody('Eric Geboers'); document.getElementById("arrow7").innerHTML = result5; </script>
If the arrow function body contains one statement, you can omit the curly braces and "return" keyword, then the expression will be implicitely returned. The form when the curly braces are omitted is named an inline arrow function. Omitting the curly braces works flawlessly most of the time but with one exception. When returning an object literal, you have to wrap the literal into a pair of parentheses.
examples
greet somebody =>
<p class="spec"> greet somebody => <span id="arrow8"></span></p> <script> const greetPerson_a = who => ({message: `Hello, ${who}!`}); result6 = greetPerson_a('Stan Abbeloos'); console.log(result6); document.getElementById("arrow8").textContent = JSON.stringify(result6); </script>
implicit return: examples
sum => 1 + 2 = ;
implicit return => ;
implict return =>
<p class="spec"><b> sum => 1 + 2 = <span id="arrow7A"></span> ; <br> implicit return => <span id="arrow7B"></span> ; <br> implict return => <span id="arrow7C"></span></p> <script> const sumA = (a, b) => a + b; resultC = sumA(1, 2); document.getElementById("arrow7A").innerHTML = resultC; const myFunction = () => 'test'; myFunction() //'test' console.log(myFunction()); document.getElementById("arrow7B").innerHTML = myFunction(); const thisFunction = () => ({ value: 'test' }) thisFunction() //{value: 'test'} console.log(thisFunction()); document.getElementById("arrow7C").innerHTML = thisFunction().value; </script>
P.S. function declaration and function expression are considered to be regular functions.
Inside of a regular JavaScript function, "this" value (a.k.a. the execution context) is dynamic, what means that the value of "this" depends on how the function is invoked, i.e.
1/ during a "simple invocation" the value of "this" equals to the global object (or undefined if the function runs in strict mode),
2/ during a "method invocation" the value of "this" is the object owning the method,
3/ during an "indirect invocation" using myFunc.call(thisVal, arg1, ..., argN) or myFunc.apply(thisVal, [arg1, ..., argN]) the value of "this" equals to the first argument,
4/ during a "constructor invocation" using "new" keyword "this" equals to the newly created instance.
"this" value inside of an arrow function always equals "this" value from the outer function. In other words, the arrow function resolves this lexically.
examples: "this" keyword
arrow:
regular:
<div> <p style="margin-left:5vw;">arrow: <span id="one"></span></p> <p style="margin-left:5vw;">regular: <span id="two"></span></p> </div> <script> let user = { name: "Alexander", this1:() => { document.getElementById("one").innerHTML = ("Hello " + this.name + " (P.S. no 'this' binding here)"); }, this2(){ document.getElementById("two").innerHTML =("Welcome to " + this.name + " (P.S. 'this' binding works here)"); } }; user.this1(); user.this2(); </script>
examples: "this" keyword.
arrow:
regular:
<div> <p style="margin-left:5vw;">arrow: <span id="one_A"></span></p> <p style="margin-left:5vw;">regular: <span id="two_A"></span></p> </div> <script> const car_a = { brand: 'Ford', model: 'Fiesta', start: function() { document.getElementById("two_A").innerHTML = `Started ${this.brand} ${this.model}`; }, stop: () => { document.getElementById("one_A").innerHTML = `Stopped ${this.brand} ${this.model}`; } } car_a.start(); car_a.stop(); </script>
the regular function can easily construct objects.
the arrow function cannot be used as a constructor. Arrow functions do not have a prototype property and they cannot be used with "new".
examples: constructor
arrow:
regular:
regular:
<div> <p style="margin-left:5vw;">arrow: <span id="three"></span></p> <p style="margin-left:5vw;">regular: <span id="four"></span></p> <p style="margin-left:5vw;">regular: <span id="four_A"></span></p> </div> <script> let Person = function(name, height) { this.name = name this.height = height } Person.prototype.hello = function() { console.log('Hi, my name is ' + this.name) document.getElementById("four").innerHTML = ("Hi, my name is " + this.name); } let alice = new Person('Alice', 1.7) alice.hello() // Hi, my name is Alice var My_function = new Function("a","b","return a+b") var x = My_function(2,3) document.getElementById("four_A").innerHTML = "The sum is " + x </script>
regular function: inside the body of a regular function, "arguments" is a special array-like object containing the list of arguments with which the function has been invoked.
arrow function: no "arguments" special keyword is defined inside an arrow function. The "arguments" object is resolved lexically: the arrow function accesses "arguments" from the outer function.
examples: arguments
arrow:
regular:
regular:
<div> <p style="margin-left:4vw;">arrow: <span id="five"></span></p> <p style="margin-left:4vw;">regular: <span id="six"></span></p> <p style="margin-left:4vw;">regular: <span id="seven"></span></p> </div> <script> function myFunctionA() { console.log(arguments); } myFunctionA('a', 'b'); // logs { 0: 'a', 1: 'b', length: 2 } function myRegularFunction() { const myArrowFunction = () => { console.log(arguments); } myArrowFunction('c', 'd'); } myRegularFunction('a', 'b'); // logs { 0: 'a', 1: 'b', length: 2 } </script>
regular function: "return" expression statement returns the result from a function. If the "return" statement is missing, or there's no expression after "return" statement, the regular function implicitely returns undefined.
arrow function: you can return values from the arrow function the same way as from a regular function, but with one useful exception. If the arrow function contains one expression, and you omit the function's curly braces, then the expression is implicitly returned. These are the "inline arrows function".
examples: implicit return
arrow:
arrow:
<div> <p style="margin-left:4vw;">arrow: <span id="eight"></span></p> <p style="margin-left:4vw;">arrow: <span id="eight_A"></span></p> </div> <script> var func = xx => xx * xx; func(10); result = func(10); // concise body syntax, implied "return" document.getElementById("eight").innerHTML = result; var func1 = (xy, z) => { return xy + z; }; func1(4, 5); result1 = func1(4, 5) // with block body, explicit "return" needed document.getElementById("eight_A").innerHTML = result1; </script>
regular functions are the usual way to define methods on classes.
arrow functions: thanks to "Class fields proposal" (at this moment at stage 3) you can use the arrow function as methods inside classes. Now, in contrast with regular functions, the method defined using an arrow binds this lexically to the class instance.
examples: methods
arrow:
arrow:
<div> <p style="margin-left:7vw;">arrow: <span id="eleven"></span></p> <p style="margin-left:7vw;">arrow: <span id="eleven_A"></span></p> </div> <script> 'use strict'; var obj = { // does not create a new scope i: 10, b: () => console.log(this.i, this), c: function() { console.log(this.i, this); } } obj.b(); // prints undefined, Window {...} (or the global object) obj.c(); // prints 10, Object {...} document.getElementById("eleven").innerHTML = obj.b(); document.getElementById("eleven_A").innerHTML = obj.c(); </script>
examples
without parantheses: 5 * 2 =
with parantheses: 5 * 2 =
;
<div> <p>without parantheses: 5 * 2 = <span id="arrow9"></span></p> <p>with parantheses: 5 * 2 = <span id="arrow10"></span></p> <p>; <span id="arrow11"></span></p> </div> <script> const double = x => x*2; resultA = double(5); document.getElementById("arrow9").innerHTML = resultA; const doubleB = (x) => x*2; resultB = doubleB(5); document.getElementById("arrow10").innerHTML = resultB; var Add = (num1, num2) => { return (num1+num2) } document.getElementById("arrow11").innerHTML = "sum of 10 and 20 is "+ Add(10, 20); </script>